class EventBus<ADDRTYPE> {
    private idCounter: number[] = []
    private handlers: { [address: string]: { [id: number]: (bus: EventBus<ADDRTYPE>, data: any) => void } } = {}

    public subscribe<T>(address: ADDRTYPE, handler: (bus: EventBus<ADDRTYPE>, data: T) => void): number {
        const stringOfAddress = address.toString()
        let id = 0;
        while (this.idCounter.filter(innerId => innerId == id).length > 0) {
            id++
        }

        let handlerContainer = this.handlers[stringOfAddress]
        if (handlerContainer == null) {
            handlerContainer = {}
            this.handlers[stringOfAddress] = handlerContainer
        }

        handlerContainer[id] = handler

        this.idCounter.push(id)
        return id
    }

    public unSubscribe(handlerId: number): void {
        for (let addressKey in this.handlers) {
            for (let handlerIndex in this.handlers[addressKey]) {
                if (handlerIndex == handlerId.toString()) {
                    delete this.handlers[addressKey][handlerIndex]
                }
            }
        }
    }

    public unSubscribeAll(handlersId: number[]): void {
        handlersId.forEach(id => this.unSubscribe(id))
    }

    public publish(address: ADDRTYPE, data: any): void {
        const stringOfAddress = address.toString()
        for (let key in this.handlers[stringOfAddress]) {
            this.handlers[stringOfAddress][key](this, data)
        }
    }

    private static instances: { [key: string]: EventBus<any> } = {}
    public static SingleInstance<ADDRTYPE>(key: string): EventBus<ADDRTYPE> {
        let bus = this.instances[key]
        if (bus == null) {
            bus = new EventBus<ADDRTYPE>()
            this.instances[key] = bus
        }
        return bus
    }
}

export { EventBus }